#
#   Copyright (C) 2007 Jonas Nockert
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   See http://www.gnu.org/licenses/
#
#   --------------------------------------------------------------------
#
#   changes 0.0.1: First release
#
#   Based on PostVox (http://code.sixapart.com/trac/mtplugins/wiki/PostVox)
#

package MT::Plugin::PostTwitter;

use strict;
use warnings;
use base qw(MT::Plugin);
use MT 4.0;
use MT::Util;
use MIME::Base64;
use LWP::UserAgent;
require HTTP::Headers;

our $VERSION = '0.01';
my $plugin = __PACKAGE__->new({
    name            => 'Post to Twitter',
    description     => 'Automatic cross-posting to Twitter (MT4 only)',
    author_name     => 'Jonas Nockert',
    author_link     => 'http://jonas.lemonad.org/',
    version         => $VERSION,
    icon            => 'PostTwitter.png',
    settings        => new MT::PluginSettings([
        ['twitter_username'], ['twitter_password'],
        ['twitter_preface'], ['use_tinyurl'],
        ['always_post'],
    ]),
    blog_config_template => 'posttwitter.tmpl',
});

MT->add_plugin($plugin);
MT->add_callback('MT::App::CMS::template_param.edit_entry', 9, $plugin, \&add_input_field);
MT->add_callback('cms_post_save.entry', 9, $plugin, \&hdlr_post_save);
MT->add_callback('api_post_save.entry', 9, $plugin, \&hdlr_api_post_save);

# Modify the Edit Entry screen within MT
sub add_input_field {
  my ($eh, $app, $param, $tmpl) = @_;
  return unless UNIVERSAL::isa($tmpl, 'MT::Template');

  my $q = $app->param;
  my $blog_id = $q->param('blog_id');
  my $config = $plugin->get_config_hash('blog:' . $blog_id . ':user:' . $app->user->id);
  return unless ( $config->{twitter_username} || $config->{twitter_password} );

  my $entry_class = MT->model('entry');
  my $entry_id = $app->param('id');
  my $entry;
  if ($entry_id) {
      $entry = $entry_class->load($entry_id, { cached_ok => 1 });
  }
  my $innerHTML;
  my $already_posted = $entry && (($entry->tangent_cache || '') =~ m!http://twitter.com/!);
  if ($already_posted) {
    $innerHTML = '<input type="checkbox" id="allow_posttwitter" name="allow_posttwitter" value="1" /> Cross post to Twitter again?';
  } else {
    my $checked = '';
    if($config->{always_post}) {
      $checked = 'checked="checked" ';
    }
    $innerHTML = '<input type="checkbox" id="allow_posttwitter" name="allow_posttwitter" ' . $checked . 'value="1" />Cross post to Twitter?';
  }

  my $host_node;
  my $block_node;
  if(!($host_node = $tmpl->getElementById('status'))) {
    MT->log({ message => "Cannot get the status block.", });
    return $app->error('Cannot get the status block');
  }
  if(!($block_node = $tmpl->createElement('app:setting', {
      id => 'allow_posttwitter',
      label => 'Cross Posting' }))) {
    MT->log({ message => "Cannot create the element.", });
    return $app->error('Cannot create the element');
  }
  $block_node->innerHTML( $innerHTML );
  if(!($tmpl->insertBefore($block_node, $host_node))) {
    MT->log({ message => "Failed to insertBefore.", });
    return $app->error('Failed to insertBefore.');
  }
}

sub hdlr_api_post_save {
    return $plugin->_cross_post(@_);
}

sub hdlr_post_save {
    my ($eh, $app, $obj, $original) = @_;
    return $obj unless $app->param('allow_posttwitter');
    return $plugin->_cross_post($eh, $app, $obj, $original);
}

# $obj is the entry (has already been saved at this point)
sub _cross_post {
  my $self = shift;
  my ($eh, $app, $obj, $original) = @_;
  my $blog_id = $obj->blog_id;
  my $user_id = $obj->author_id;
  my $permalink = $obj->permalink();
  my $config = $plugin->get_config_hash('blog:'.$blog_id.':user:'.$user_id);
  return $obj unless ( $config->{twitter_username} && $config->{twitter_password} );

  require MT::Blog;
  my $blog = MT::Blog->load($blog_id);
  my $blog_url = $blog->site_url();

  my $entry_class = MT->model('entry');
  return $obj if $obj->status != MT::Entry::RELEASE();

  my $new_post = 1;
  if ( $obj->tangent_cache && $obj->tangent_cache =~ m!(http://twitter.com/)!i) {
    $new_post = 0;
  }

  require MT::I18N;
  my $enc = MT->instance->config('PublishCharset') || undef;
  my $text = MT::I18N::encode_text($obj->title , $enc, 'utf-8' );
  my $twitter_preface = MT::I18N::encode_text($config->{twitter_preface}, $enc, 'utf-8');

  # Setup
  my $res;
  my $ua = MT->new_ua( { timeout => MT->config->PingTimeout } );

  # Use tinyurl to shorten permalink
  my $use_tinyurl = $config->{use_tinyurl};
  if($use_tinyurl) {
    $res = $ua->get("http://tinyurl.com/api-create.php?url=$permalink");
    if(!($res->is_success)) {
      MT->log({ message => "Could not tinyurl permalink ($permalink" . $res->content . ').', });
      return $app->error("Could not tinyurl permalink ($permalink).");
    }
    my $tinyurl = $res->content;
    if($tinyurl !~ m/^http:\/\//i) {
      MT->log({ message => "Could not tinyurl permalink ($permalink, $tinyurl).", });
    } else {
      $permalink = $tinyurl;
    }
  }

  # Prepare basic authorization
  my $twitter_username = $config->{twitter_username};
  my $twitter_password = $config->{twitter_password};
  $ua->credentials("twitter.com:80", "Twitter API", $twitter_username => $twitter_password);

  # Post to Twitter
  my $twitter_message = "$twitter_preface \"$text\" ($permalink)";
  $res = $ua->post('http://twitter.com/statuses/update.json',
        {
          status        => $twitter_message
        });
  if(!($res->is_success)) {
    MT->log({ message => 'Failed to cross post to Twitter! (' . $res->content . ').', });
    return $app->error('Failed to cross post to Twitter! (' . $res->content . ').');
  }
  MT->log({ message => "Cross posted \"$text\" ($permalink) to Twitter.", });

  # Save url to tangent_cache to indicate that this post has already been cross posted
  my @t = split /\s+/, ( $obj->tangent_cache || '' );
  push @t, 'http://twitter.com/';
  $obj->tangent_cache( join ' ', @t );
  $obj->save;
  return($obj);
}

# Since these settings are blog *and* user specific, automatically assign
# the user id to the scope element of all load/save/reset operations
# that operate on the blog scope.

sub load_config {
    my $plugin = shift;
    my $app = MT->instance;
    return unless $app->can('user');

    my ($param, $scope) = @_;
    $scope .= ':user:' . $app->user->id if $scope =~ m/^blog:/;
    $plugin->SUPER::load_config($param, $scope);
}

sub save_config {
    my $plugin = shift;
    my $app = MT->instance;
    return unless $app->can('user');

    my ($param, $scope) = @_;
    $scope .= ':user:' . $app->user->id if $scope =~ m/^blog:/;
    $plugin->SUPER::save_config($param, $scope);
}

sub reset_config {
    my $plugin = shift;
    my $app = MT->instance;
    return unless $app->can('user');
    my ($scope) = @_;
    $scope .= ':user:' . $app->user->id if $scope =~ m/^blog:/;
    $plugin->SUPER::reset_config($scope);
}
